package com.test.context;

import com.test.exception.BeansException;
import com.test.factory.ConfigurableListableBeanFactory;
import com.test.factory.DefaultListableBeanFactory;

/**
 * 抽象可刷新应用上下文类，继承自AbstractApplicationContext
 * 提供了刷新Bean工厂的方法和机制，包括Bean工厂的创建、刷新和获取
 */
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext{

    // Bean工厂实例，用于管理Bean的创建、配置和生命周期
    private DefaultListableBeanFactory beanFactory;

    /**
     * 获取一个新鲜的Bean工厂实例
     * 此方法首先调用refreshBeanFactory()方法刷新Bean工厂，然后返回新的Bean工厂实例
     * @return ConfigurableListableBeanFactory 配置列表化的Bean工厂
     */
    @Override
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() throws Exception {
        refreshBeanFactory();
        return getBeanFactory();
    }

    /**
     * 刷新Bean工厂的方法
     * 如果当前Bean工厂不为空，则先销毁单例Bean，然后设置为null
     * 创建一个新的Bean工厂实例，加载Bean定义，最后将其赋值给成员变量
     * @throws BeansException 当刷新Bean工厂过程中出现异常时抛出
     */
    protected void refreshBeanFactory() throws Exception {
        if (this.beanFactory != null){
            this.beanFactory.destroySingletons();
            this.beanFactory = null;
        }
        DefaultListableBeanFactory beanFactory = createBeanFactory();

        loadBeanDefinitions(beanFactory);

        this.beanFactory = beanFactory;
    }

    /**
     * 创建Bean工厂的方法
     * 此方法返回一个新的DefaultListableBeanFactory实例
     * @return DefaultListableBeanFactory 默认的列表化Bean工厂
     */
    protected DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory();
    }

    /**
     * 加载Bean定义的方法，由子类实现
     * 此方法负责将Bean定义加载到指定的Bean工厂中
     * @param beanFactory DefaultListableBeanFactory 要加载Bean定义的Bean工厂
     * @throws Exception 当加载Bean定义过程中出现异常时抛出
     */
    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws Exception;

    /**
     * 获取Bean工厂实例
     * 如果Bean工厂为null，抛出IllegalStateException异常
     * @return ConfigurableListableBeanFactory 配置列表化的Bean工厂
     * @throws IllegalStateException 当Bean工厂未初始化或已关闭时抛出
     */
    @Override
    public final ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException {
        if (this.beanFactory == null){
            throw new IllegalStateException("beanFactory未初始化或已关闭");
        }
        //TODO
        //return this.beanFactory;
        return this.beanFactory;
    }

}
